package com.linciping.treeview;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

public abstract class TreeAdapter<VH extends RecyclerView.ViewHolder, N extends Node<N>> extends RecyclerView.Adapter<VH> {

    private int maxLevel = 0;

    /**
     * 原始数据
     */
    private final List<N> nodeList;

    /**
     * 列表数据
     */
    private final List<N> treeNodeList = new ArrayList<>();

    private final List<N> showTreeNodeList = new ArrayList<>();

    public TreeAdapter(List<N> nodeList) {
        this.nodeList = nodeList;
        nodeList2TreeNodeList();
        this.showTreeNodeList.addAll(treeNodeList);
    }

    private void nodeList2TreeNodeList() {
        if (CheckUtil.isCollectionEmpty(nodeList)) {
            return;
        }
        for (N child : nodeList) {
            int childCount = recursiveNode(child, 0);
            child.setAllChildCount(childCount);
        }
    }

    protected boolean isShowExpand(N n) {
        return !n.isMinChildren(maxLevel);
    }

    private int recursiveNode(N node, int level) {
        treeNodeList.add(node);
        node.setLevel(level);
        if (maxLevel < level) {
            maxLevel = level;
        }
        if (CheckUtil.isCollectionEmpty(node.getChildrenList())) {
            return 0;
        }
        int childCount = node.getChildrenList().size();
        level++;
        for (N child : node.getChildrenList()) {
            int count = recursiveNode(child, level);
            child.setAllChildCount(count);
            childCount += count;
        }
        return childCount;
    }

    public int backgroundType(N node, int position) {
        if (node.getBackgroundRes() != -1) {
            return node.getBackgroundRes();
        }
        int backgroundRes;
        N preNode = position == 0 ? null : showTreeNodeList.get(position - 1);
        N nextNode = position == (getItemCount() - 1) ? null : showTreeNodeList.get(position + 1);
        if (node.isMinChildren(maxLevel)) {
            boolean isStartChildren = preNode == null || !preNode.isMinChildren(maxLevel);
            boolean isEndChildren = nextNode == null || !nextNode.isMinChildren(maxLevel);
            if (isStartChildren && isEndChildren) {
                backgroundRes = R.drawable.shape_node;
            } else if (isStartChildren && !isEndChildren) {
                backgroundRes = R.drawable.shape_node_top;
            } else if (!isStartChildren && isEndChildren) {
                backgroundRes = R.drawable.shape_node_bottom;
            } else {
                backgroundRes = R.drawable.shape_node_mid;
            }
        } else {
            backgroundRes = R.drawable.shape_parent;
        }
        node.setBackgroundRes(backgroundRes);
        return backgroundRes;
    }

    @Override
    public int getItemCount() {
        return showTreeNodeList.size();
    }

    @Override
    public void onBindViewHolder(@NonNull VH holder, int position) {
        N node = showTreeNodeList.get(position);
        holder.itemView.setBackgroundResource(backgroundType(node, position));
        int paddingRight = holder.itemView.getPaddingRight();
        int paddingTop = holder.itemView.getPaddingTop();
        int paddingBottom = holder.itemView.getPaddingBottom();
        int padding = 36 * node.getLevel();
        holder.itemView.setPadding(padding, paddingTop, paddingRight, paddingBottom);
        onBindViewHolder(holder, position, node);
    }

    protected abstract void onBindViewHolder(@NonNull VH holder, int position, N node);

    protected void setExpand(N node, int position) {
        node.toggleExpand();
        if (node.isExpand()) {
            expand(node, position);
        } else {
            fold(node, position);
        }
    }


    private void expand(N node, int position) {
        int allChildCount = node.getAllChildCount();
        int startPosition = position + 1;
        for (int i = 0; i < allChildCount; i++) {
            int index = i + startPosition;
            showTreeNodeList.add(index, treeNodeList.get(index));
        }
        notifyItemRangeInserted(startPosition, allChildCount);
    }

    private void fold(N node, int position) {
        int allChildCount = node.getAllChildCount();
        int startPosition = position + allChildCount;
        for (int i = startPosition; i > position; i--) {
            showTreeNodeList.remove(i);
        }
        notifyItemRangeRemoved(position + 1, allChildCount);
    }
}
